package com.yanqu.road.server.manager.yrank;

import com.yanqu.road.entity.activity.ActivityConditionInfo;
import com.yanqu.road.entity.activity.suitang.entity.rank.CrossSuiTangRankSort;
import com.yanqu.road.entity.activity.suitang.entity.rank.CrossSuiTangYRankSort;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.rank.cross.CrossUserRank;
import com.yanqu.road.entity.rank.yrank.UnionYRank;
import com.yanqu.road.entity.rank.yrank.UserYRank;
import com.yanqu.road.entity.task.args.UnionRiseRankArgs;
import com.yanqu.road.entity.union.UnionBaseInfo;
import com.yanqu.road.logic.bussiness.rank.YRankBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.logic.pb.CrossRankPb;
import com.yanqu.road.logic.sort.LangYaBuildingRankSort;
import com.yanqu.road.logic.sort.yrank.*;
import com.yanqu.road.pb.rank.RankProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.manager.activity.ActivityInfoMgr;
import com.yanqu.road.utils.ListHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class CrossYRankMgr extends TempMgr {

    private static final Map<Integer, Map<Integer, Map<String, Map<Long, UserYRank>>>> userMap = new ConcurrentHashMap<>();
    private static final Map<Integer, Map<Integer, Map<String, Map<String, UnionYRank>>>> unionMap = new ConcurrentHashMap<>();

    public static void userRankChange(UserYRank userYRank) {
        synchronized (userMap) {
            checkUserMapLoadDb(userYRank.getActivityId());
            userMap.get(userYRank.getActivityId()).putIfAbsent(userYRank.getGroupId(), new ConcurrentHashMap<>());
            userMap.get(userYRank.getActivityId()).get(userYRank.getGroupId()).putIfAbsent(userYRank.getIdKey(), new ConcurrentHashMap<>());
            Map<Long, UserYRank> map = userMap.get(userYRank.getActivityId()).get(userYRank.getGroupId()).get(userYRank.getIdKey());

            UserYRank oldData = map.get(userYRank.getUserId());
            if (oldData != null) {
                if (userYRank.getIdKey().equals(String.valueOf(eGamePlayerEventType.UnionExpRiseRank.getValue()))) {
                    // 商会经验榜单只增不减
                    if (userYRank.getValue().compareTo(oldData.getValue()) > 0) {
                        oldData.updateRankData(userYRank);
                    }
                } else {
                    oldData.updateRankData(userYRank);
                }
            } else {
                userYRank.setInsertOption();
                map.put(userYRank.getUserId(), userYRank);
            }
        }
    }

    public static void unionUserRankChange(UserYRank userYRank, String unionUid, UnionBaseInfo unionBaseInfo, ConcurrentHashMap<Long, Integer> posMap, int changeType) {
        // 更新个人
        userRankChange(userYRank);

        // 更新商会
        if (StringUtils.isNullOrEmpty(unionUid)) {
            return;
        }
        unionRankChange(userYRank.getActivityId(), userYRank.getGroupId(), userYRank.getIdKey(), unionUid, unionBaseInfo, posMap, changeType, userYRank.getUpdateTime(), null);
    }

    /**
     * @param unionBaseInfo 可以null，不更新
     * @param posMap        可以null，不更新
     * @param param         可以null，不更新
     */
    public static void unionRankChange(int activityId, int groupId, String idKey, String unionUid,
                                       UnionBaseInfo unionBaseInfo, ConcurrentHashMap<Long, Integer> posMap,
                                       int changeType, long updateTime, String param) {
        synchronized (unionMap) {
            checkUnionMapLoadDb(activityId);
            unionMap.get(activityId).putIfAbsent(groupId, new ConcurrentHashMap<>());
            unionMap.get(activityId).get(groupId).putIfAbsent(idKey, new ConcurrentHashMap<>());
            Map<String, UnionYRank> map = unionMap.get(activityId).get(groupId).get(idKey);

            // 生成一条数据
            UnionYRank oldData = map.get(unionUid);
            if (oldData == null) {
                oldData = new UnionYRank();
                oldData.setActivityId(activityId);
                oldData.setGroupId(groupId);
                oldData.setIdKey(idKey);
                oldData.setUnionUid(unionUid);
                oldData.setInsertOption();
                map.put(oldData.getUnionUid(), oldData);
            }

            // 更新信息
            if (unionBaseInfo != null) {
                oldData.setUnionBaseInfo(unionBaseInfo);
            }
            if (changeType == UnionRiseRankArgs.NOTIFY_TYPE_DELETE) {
                posMap = new ConcurrentHashMap<>(); // 删除商会只要清空成员
            }
            if (posMap != null) { // 没有数据就不设置了
                oldData.setPosMap(posMap);
            }

            if (param != null) {
                if (Integer.valueOf(idKey) == eGamePlayerEventType.PeakStrongHoldUnionIntegralRank.getValue()) {
                    List<BigInteger> bigIntegers = StringUtils.stringToBigIntegerList(param, "=");
                    oldData.setValue(bigIntegers.get(0));
                    oldData.setParam(bigIntegers.get(1).toString());
                } else if (Integer.valueOf(idKey) == eGamePlayerEventType.SuiTangUnionScoreRank.getValue()) {
                    List<String> params = StringUtils.stringToStringList(param, "=");
                    oldData.setValue(new BigInteger(params.get(0)));
                    oldData.setParam(params.get(1));
                    oldData.setUpdateTime(updateTime);
                }  else if (Integer.valueOf(idKey) == eGamePlayerEventType.HsIslandUnionRank.getValue()) {
                    List<String> params = StringUtils.stringToStringList(param, "=");
                    oldData.setValue(new BigInteger(params.get(0)));
                    oldData.setParam(params.get(1));
                    oldData.setUpdateTime(updateTime);
                } else {
                    if (param != null) {
                        oldData.setParam(param);
                    }
                }
            }

            // 重新计算值
            oldData.changeValue(calcUnionValue(oldData), updateTime);
        }
    }

    public static List<UserYRank> getSortUserRankList(int activityId, int groupId, String idKey) {
        checkUserMapLoadDb(activityId);
        Map<Integer, Map<String, Map<Long, UserYRank>>> map = userMap.get(activityId);
        if (map == null) {
            return new ArrayList<>();
        }
        Map<String, Map<Long, UserYRank>> map2 = map.get(groupId);
        if (map2 == null) {
            return new ArrayList<>();
        }
        Map<Long, UserYRank> map3 = map2.get(idKey);
        if (map3 == null) {
            return new ArrayList<>();
        }
        List<UserYRank> list = new ArrayList<>(map3.values());

        // 长度
        int maxRank = getMaxRank(activityId, idKey);

        // 排序
        if (Integer.valueOf(idKey) == eGamePlayerEventType.LangYaUserBuildingCoinRank.getValue()){      //琅琊榜特殊处理一下
            list = list.stream().sorted(new LangYaBuildingRankSort()).limit(maxRank).collect(Collectors.toList());
        }else {
            list = list.stream().sorted(new UserYRankSort()).limit(maxRank).collect(Collectors.toList());
        }

        return list;
    }

    public static List<UserYRank> getSortUnionContributionList(int activityId, int groupId, String idKey, String unionUid) {
        UnionYRank unionYRank = getUnionYRank(activityId, groupId, idKey, unionUid);
        if (unionYRank == null) {
            return new ArrayList<>();
        }

        List<UserYRank> list = new ArrayList<>();
        for (long memberId : unionYRank.getPosMap().keySet()) {
            UserYRank userYRank = getUserYRank(activityId, groupId, idKey, memberId);
            if (userYRank != null) {
                list.add(userYRank);
            }
        }

        // 排序
        list = list.stream().sorted(new UserYRankSort()).collect(Collectors.toList());

        return list;
    }

    /*
     * getSortUnionContributionList 从不同榜中，获取成员的排行
     */
    public static List<UserYRank> getSortUnionContributionList(int activityId, int groupId, String idKeyUnion, String idKeyUser, String unionUid) {
        UnionYRank unionYRank = getUnionYRank(activityId, groupId, idKeyUnion, unionUid);
        if (unionYRank == null) {
            return new ArrayList<>();
        }

        List<UserYRank> list = new ArrayList<>();
        for (long memberId : unionYRank.getPosMap().keySet()) {
            UserYRank userYRank = getUserYRank(activityId, groupId, idKeyUser, memberId);
            if (userYRank != null) {
                list.add(userYRank);
            }
        }

        // 排序
        list = list.stream().sorted(new UserYRankSort()).collect(Collectors.toList());

        return list;
    }


    public static List<UnionYRank> getSortUnionRankList(int activityId, int groupId, String idKey) {
        checkUnionMapLoadDb(activityId);
        Map<Integer, Map<String, Map<String, UnionYRank>>> map = unionMap.get(activityId);
        if (map == null) {
            return new ArrayList<>();
        }
        Map<String, Map<String, UnionYRank>> map2 = map.get(groupId);
        if (map2 == null) {
            return new ArrayList<>();
        }
        Map<String, UnionYRank> map3 = map2.get(idKey);
        if (map3 == null) {
            return new ArrayList<>();
        }
        List<UnionYRank> list = new ArrayList<>(map3.values());

        // 长度
        int maxRank = getMaxRank(activityId, idKey);

        // 排序
        list = list.stream().sorted(getUnionComparator(idKey)).limit(maxRank).collect(Collectors.toList());

        return list;
    }

    public static int getUserRankNum(List<UserYRank> list, long userId) {
        int maxRank = list.size() > 0 ? getMaxRank(list.get(0).getActivityId(), list.get(0).getIdKey()) : GameConfig.RANK_DEFAULT_MAX_COUNT;

        int rankNum = 0;
        for (UserYRank rank : list) {
            rankNum++;
            if (rankNum > maxRank) {
                return -1;
            }
            if (rank.getUserId() == userId) {
                return rankNum;
            }
        }
        return -1;
    }

    public static int getUnionRankNum(List<UnionYRank> sortList, String unionUid) {
        int maxRank = sortList.size() > 0 ? getMaxRank(sortList.get(0).getActivityId(), sortList.get(0).getIdKey()) : GameConfig.RANK_DEFAULT_MAX_COUNT;

        int rankNum = 0;
        for (UnionYRank rank : sortList) {
            rankNum++;
            if (rankNum > maxRank) {
                return -1;
            }
            if (Objects.equals(rank.getUnionUid(), unionUid)) {
                return rankNum;
            }
        }
        return -1;
    }

    public static int getUnionRankNum(List<UnionYRank> sortList, long userId) {
        int maxRank = sortList.size() > 0 ? getMaxRank(sortList.get(0).getActivityId(), sortList.get(0).getIdKey()) : GameConfig.RANK_DEFAULT_MAX_COUNT;

        int rankNum = 0;
        for (UnionYRank rank : sortList) {
            rankNum++;
            if (rankNum > maxRank) {
                return -1;
            }
            if (rank.getPosMap().containsKey(userId)) {
                return rankNum;
            }
        }
        return -1;
    }

    public static int getMaxRank(int activityId, String idKey) {
        int maxRank = 0;
        List<ActivityConditionInfo> conditionInfoList = ActivityInfoMgr.getConditionInfoList(activityId, Integer.valueOf(idKey));
        if (conditionInfoList != null) {
            maxRank = ActivityHelper.getMaxRank(conditionInfoList);
        }
        if (maxRank <= 0) {
            maxRank = GameConfig.RANK_DEFAULT_MAX_COUNT;
        }
        return maxRank;
    }

    private static BigInteger calcUnionValue(UnionYRank unionYRank) {
        int activityId = unionYRank.getActivityId();
        int groupId = unionYRank.getGroupId();
        String idKey = unionYRank.getIdKey();
        ArrayList<Long> memberList = new ArrayList<>(unionYRank.getPosMap().keySet());

        BigInteger value = BigInteger.ZERO;
        checkUserMapLoadDb(activityId);

        //巅峰据点战,直接取商会分数
        if (Integer.valueOf(idKey) == eGamePlayerEventType.PeakStrongHoldUnionIntegralRank.getValue() ||
                Integer.valueOf(idKey) == eGamePlayerEventType.SuiTangUnionScoreRank.getValue() ||
                Integer.valueOf(idKey) == eGamePlayerEventType.HsIslandUnionRank.getValue()) {
            value = unionYRank.getValue();
            return value;
        }

        Map<Integer, Map<String, Map<Long, UserYRank>>> map1 = userMap.get(activityId);
        if (map1 != null) {
            Map<String, Map<Long, UserYRank>> map2 = map1.get(groupId);
            if (map2 != null) {
                Map<Long, UserYRank> map3 = map2.get(idKey);
                if (map3 != null) {
                    // 累加商会成员值
                    for (long userId : memberList) {
                        UserYRank tmpRank = map3.get(userId);
                        if (tmpRank != null) {
                            value = value.add(tmpRank.getValue());
                        }
                    }
                }
            }
        }

        // 经验冲榜：加商贸经验
        if (Integer.valueOf(idKey) == eGamePlayerEventType.UnionExpRiseRank.getValue()) {
            if (!StringUtils.isNullOrEmpty(unionYRank.getParam())) {
                value = value.add(new BigInteger(unionYRank.getParam()));
            }
        }

        return value;
    }

    public static UserYRank getUserYRank(int activityId, int groupId, String idKey, long userId) {
        checkUserMapLoadDb(activityId);
        Map<Integer, Map<String, Map<Long, UserYRank>>> map = userMap.get(activityId);
        if (map == null) {
            return null;
        }
        Map<String, Map<Long, UserYRank>> map2 = map.get(groupId);
        if (map2 == null) {
            return null;
        }
        Map<Long, UserYRank> map3 = map2.get(idKey);
        if (map3 == null) {
            return null;
        }
        return map3.get(userId);
    }

    public static UnionYRank getUnionYRank(int activityId, int groupId, String idKey, long userId) {
        checkUnionMapLoadDb(activityId);
        Map<Integer, Map<String, Map<String, UnionYRank>>> map = unionMap.get(activityId);
        if (map == null) {
            return null;
        }
        Map<String, Map<String, UnionYRank>> map2 = map.get(groupId);
        if (map2 == null) {
            return null;
        }
        Map<String, UnionYRank> map3 = map2.get(idKey);
        if (map3 == null) {
            return null;
        }
        for (UnionYRank rank : map3.values()) {
            if (rank.getPosMap().containsKey(userId)) {
                return rank;
            }
        }
        return null;
    }

    public static UnionYRank getUnionYRank(int activityId, int groupId, String idKey, String unionUid) {
        checkUnionMapLoadDb(activityId);
        Map<Integer, Map<String, Map<String, UnionYRank>>> map = unionMap.get(activityId);
        if (map == null) {
            return null;
        }
        Map<String, Map<String, UnionYRank>> map2 = map.get(groupId);
        if (map2 == null) {
            return null;
        }
        Map<String, UnionYRank> map3 = map2.get(idKey);
        if (map3 == null) {
            return null;
        }
        for (UnionYRank rank : map3.values()) {
            if (Objects.equals(rank.getUnionUid(), unionUid)) {
                return rank;
            }
        }
        return null;
    }


    @Override
    public boolean init() throws Exception {
        return true;
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    @Override
    public boolean save() {

        for (Map<Integer, Map<String, Map<Long, UserYRank>>> map : userMap.values()) {
            for (Map<String, Map<Long, UserYRank>> map2 : map.values()) {
                for (Map<Long, UserYRank> map3 : map2.values()) {
                    for (UserYRank rank : map3.values()) {
                        try {
                            if (rank.isInsertOption()) {
                                YRankBussiness.addUserYRank(rank);
                            } else if (rank.isUpdateOption()) {
                                YRankBussiness.updateUserYRank(rank);
                            }
                        } catch (Exception e) {
                            getLogger().error("error : ", e);
                        }
                    }
                }
            }
        }

        for (Map<Integer, Map<String, Map<String, UnionYRank>>> map : unionMap.values()) {
            for (Map<String, Map<String, UnionYRank>> map2 : map.values()) {
                for (Map<String, UnionYRank> map3 : map2.values()) {
                    for (UnionYRank rank : map3.values()) {
                        try {
                            if (rank.isInsertOption()) {
                                YRankBussiness.addUnionYRank(rank);
                            } else if (rank.isUpdateOption()) {
                                YRankBussiness.updateUnionYRank(rank);
                            }
                        } catch (Exception e) {
                            getLogger().error("error : ", e);
                        }
                    }
                }
            }
        }

        CrossYRankCacheMgr.expireCheck();

        return true;
    }

    private static void checkUserMapLoadDb(int activityId) {
        if (!userMap.containsKey(activityId)) {
            synchronized (userMap) {
                if (!userMap.containsKey(activityId)) {
                    Map<Integer, Map<String, Map<Long, UserYRank>>> map = YRankBussiness.getUserYRankMap(activityId);
                    userMap.put(activityId, map);
                }
            }
        }
    }

    private static void checkUnionMapLoadDb(int activityId) {
        if (!unionMap.containsKey(activityId)) {
            synchronized (unionMap) {
                if (!unionMap.containsKey(activityId)) {
                    Map<Integer, Map<String, Map<String, UnionYRank>>> map = YRankBussiness.getUnionYRankMap(activityId);
                    unionMap.put(activityId, map);
                }
            }
        }
    }

    public static int getSortUnionRankListMaxNum(int activityId, int groupId, String idKey){
        checkUnionMapLoadDb(activityId);
        Map<Integer, Map<String, Map<String, UnionYRank>>> map = unionMap.get(activityId);
        if (map == null) {
            return 0;
        }
        Map<String, Map<String, UnionYRank>> map2 = map.get(groupId);
        if (map2 == null) {
            return 0;
        }
        Map<String, UnionYRank> map3 = map2.get(idKey);
        if (map3 == null) {
            return 0;
        }
        return map3.size();
    }

    public static List<UnionYRank> getSortUnionRankListByPagePara(int activityId, int groupId, String idKey,int pageNo, int pageSize) {
        checkUnionMapLoadDb(activityId);
        Map<Integer, Map<String, Map<String, UnionYRank>>> map = unionMap.get(activityId);
        if (map == null) {
            return new ArrayList<>();
        }
        Map<String, Map<String, UnionYRank>> map2 = map.get(groupId);
        if (map2 == null) {
            return new ArrayList<>();
        }
        Map<String, UnionYRank> map3 = map2.get(idKey);
        if (map3 == null) {
            return new ArrayList<>();
        }
        List<UnionYRank> list = new ArrayList<>(map3.values());
        list = list.stream().sorted(getUnionComparator(idKey)).collect(Collectors.toList());
        int beginRank = Math.max(pageNo * pageSize + 1, 1);
        int endRank = Math.min(beginRank + pageSize - 1, list.size());

        if (beginRank > list.size()) {
            return new ArrayList<>();
        }

        if (beginRank == 1 && endRank >= list.size()) {
            return list;
        }


        List<UnionYRank> copyList = new ArrayList<>();
        int rankNo = 0;
        for (UnionYRank unionYRank : list) {
            rankNo++;
            if (rankNo < beginRank) {
                continue;
            }
            if (rankNo > endRank) {
                break;
            }
            copyList.add(unionYRank);
        }

        return copyList;
    }

    /**
     * 有特殊的商会排行比较的这里加
     * @param idKey
     * @return
     */
    public static Comparator<UnionYRank> getUnionComparator(String idKey) {
        Integer conditionType = Integer.valueOf(idKey);
        if (conditionType == eGamePlayerEventType.PeakStrongHoldUnionIntegralRank.getValue()) {
            return new UnionYRankPeakHoldSort();
        }
        if (conditionType == eGamePlayerEventType.SuiTangUnionScoreRank.getValue()) {
            return new CrossSuiTangYRankSort();
        }
        if (conditionType == eGamePlayerEventType.HsIslandUnionRank.getValue()) {
            return new UnionYRankHsIslandSort();
        }
        if (conditionType == eGamePlayerEventType.HorseRunUnionRacingScoreRank.getValue()){
            return new UnionYRankHorseRunSort();
        }
        return new UnionYRankSort();
    }

    /**
     * 获取List中指定排名前后指定数量的元素列表，不包括指定排名的元素。
     * @param rank 排名位置（以1为起始）
     * @param start 前面需要获取的元素数量
     * @param end 后面需要获取的元素数量
     * @return 包含指定排名前后元素的LinkedList，不包括指定排名的元素
     */
    public static List<UserYRank> getSubListWithoutIndex(List<UserYRank> list, int rank, int start, int end) {
        return ListHelper.getSubListWithoutIndex(list, rank - 1, start, end);
    }

}
